package com.alingrad.android.froyoengine.graphics;

import com.alingrad.android.froyoengine.graphics.renderable.Sprite;

/**
 * Class that handles frame by frame animations. Does not actually deal with any textures.
 * @author aguo
 *
 */
public class FrameByFrameAnimation extends Animation {
	public static final int TYPE_DEFAULT = 0;
	public static final int TYPE_BACKFORTH = 1;

	private Sprite[] mSprites;

	private int mFrameDelay;

	public int mFrame;
	private int mCurrentFrameTime;
	private int mFrameDirection;

	private int mAnimType;
	private boolean mRepeat;
	private boolean mIsDone;

	/**
	 * Constructs a new Animation that contains the initial data.
	 * @param frameStart The index of the first frame of the animation in the sprite array.
	 * @param frameEnd The index of the last frame of the animation in the sprite array.
	 * @param frameDelay The delay (in milliseconds) between each frame.
	 */
	public FrameByFrameAnimation(final int frameDelay, Sprite... sprites) {
		super();
		mSprites = sprites;
		mFrameDelay = frameDelay;
		mAnimType = TYPE_DEFAULT;
		mRepeat = true;
		mIsDone = false;
	}

	/**
	 * Sets the Animation type.
	 * @param animType the animation type.
	 */
	public void setType(final int animType) {
		mAnimType = animType;
	}

	/**
	 * Resets the animation to its initial state.
	 */
	public void reset() {
		mFrame = 0;
		mIsDone = false;
		mCurrentFrameTime = 0;
		if (mAnimType == TYPE_BACKFORTH)
			mFrameDirection = 1;
	}

	public Sprite getCurrentSprite() {
		return mSprites[mFrame];
	}
	
	/**
	 * Updates the animation to decide whether or not it needs to swap frames.
	 * @param delta time in milliseconds since the last update.
	 * @return the index of the current frame in the sprite array which needs to be drawn.
	 */
	public void update(final long delta) {
		if (!mIsDone) {
			mCurrentFrameTime += delta;
			if (mCurrentFrameTime < mFrameDelay)
				return;
			if (mAnimType == TYPE_DEFAULT)
				updateFrame();
			else //if (animType == TYPE_BACKFORTH)
				updateFrameBackForth();
		}
	}

	/**
	 * Updates the animation to the correct frame if the type is equal to {@link #TYPE_DEFAULT}.
	 * @return the index of the current frame in the sprite array which needs to be drawn.
	 */
	private void updateFrame() {
		int frameDelta = 0;
		while (mCurrentFrameTime > mFrameDelay) {
			mCurrentFrameTime -= mFrameDelay;
			frameDelta++;
		}
		while (frameDelta > 0) {
			frameDelta--;
			mFrame++;
			if (mRepeat) {
				if (mFrame >= mSprites.length)
					mFrame = 0;
			} else {
				mFrame = mSprites.length - 1;
				mIsDone = true;
			}
		}
	}

	/**
	 * Updates the animation to the correct frame if the type is equal to {@link #TYPE_BACKFORTH}.
	 * @return the index of the current frame in the sprite array which needs to be drawn.
	 */

	private void updateFrameBackForth() {
		int frameDelta = 0;
		while (mCurrentFrameTime > mFrameDelay) {
			mCurrentFrameTime -= mFrameDelay;
			frameDelta++;
		}
		while (frameDelta > 0) {
			frameDelta--;
			mFrame += mFrameDirection;
			if (mFrameDirection > 0) {
				if (mFrame >= mSprites.length) {
					mFrameDirection = -1;
					mFrame = mSprites.length - 2;
				}
			}
			else {
				if (mFrame < 0) {
					if (mRepeat) {
						mFrameDirection = 1;
						mFrame = 0 + 1;
					}else {
						mFrame = 0;
						mIsDone = true;
					}
				}
			}
		}
	}
}
